#! /usr/bin/python2.4

# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import shutil
import unittest

import svn.core
import svn.repos
import svn.fs

import gvn.hooks.info
import gvn.hooks.pre_commit.block_bad_path_names
import testing.hooks.common

class BadCharsTests(testing.hooks.common.HookTestCase):
  def _CheckFileName(self, filename, action="A", create_first=False):
    """Return RunHook result triple from txn based on arguments.

    Args:
      filename: file that we try to add or delete
      action: A(dd)|D(elete)
      create_first: for Delete, create the file first, bypassing the hook

    Returns:
      0 (pass), 1 (fail), string (fail and display string)

    Make a txn with data from local_path and check if author can submit it
    with its perms, or the perms from approve_user
    """

    # sanity check for tests
    self.assertTrue(action in ['A', 'D'])


    # seed argv with expected arguments during a regular call, and overwrite
    # the ones we need to, with our own values lower down
    argv = ["pre-commit", "repo_name_bogus_ignored", "txnname_bogus_ignored"]
    hi = gvn.hooks.info.HookInfo(argv, userdb='ignored')

    # plug in the actual repo and txn objects, from which hi can compute fs
    hi._repo = svn.repos.open(self.repo_name, hi.pool)

    if create_first == True:
      testing.hooks.common.CreateFile(hi.fs, "public/" + filename)

    # We don't actually need to copy a directory tree in there, but our
    # tool function does that anyway, so we let it and get the resulting
    # transaction it builds for us.
    # 5 is the revision which contains the files we might want to delete
    hi._txn = testing.hooks.common.BuildPathCopyTxn(hi.fs, "testdata", "public",
                                        "author_is_basil", "boguslog", hi.pool)

    txnroot = svn.fs.txn_root(hi._txn, hi.pool)
    if action == 'A':
      # Create a file with 'some text\n'.
      svn.fs.make_file(txnroot, 'public/' + filename, hi.pool)
      fp = svn.fs.apply_text(txnroot, 'public/' + filename, None, hi.pool)
      svn.core.svn_stream_write(fp, 'some text\n')
      svn.core.svn_stream_close(fp)
    else:
      svn.fs.delete(txnroot, 'public/' + filename, hi.pool)

    ret = gvn.hooks.pre_commit.block_bad_path_names.RunHook(hi, self._logger)

    # Delete/clean up transaction
    svn.fs.abort_txn(hi.txn, hi.pool)
    return ret

  def testNormalFile(self):
    """Check that normal files are ok.
    """
    self.assertEquals(self._CheckFileName("normal_filename"), 0)

  def testNoSpace(self):
    """Check that space is disallowed.
    """
    self.assertEquals(self._CheckFileName("space filename"),
               "' ' (space) is forbidden in pathname '/public/space filename'")

  def testNoBadChars1(self):
    """Check that a random badchar ':' is disallowed.
    """
    self.assertEquals(self._CheckFileName("bad:filename"),
               "':' (colon) is forbidden in pathname '/public/bad:filename'")

  def testNoBadChars2(self):
    """Check that a random badchar '*' is disallowed.
    """
    self.assertEquals(self._CheckFileName("bad*filename"),
                    "'*' is forbidden in pathname '/public/bad*filename'")

  def testOkFile(self):
    """Check that non OK looking filename is accepted.
    """
    self.assertEquals(self._CheckFileName("AUXme"), 0)

  def testBadWindowsFile1(self):
    """Check that non windows OK filename is refused.
    """
    self.assertEquals(self._CheckFileName("AUX"),
          "Sorry, /public/AUX contains AUX, which is not compatible with Windows")

  def testBadWindowsFile2(self):
    """Check that another non windows OK filename is refused.
    """
    self.assertEquals(self._CheckFileName("AUX.ext"),
       "Sorry, /public/AUX.ext contains AUX, which is not compatible with Windows")

  def testBadWindowsFile3(self):
    """Check that another non windows OK filename is refused.
    """
    self.assertEquals(self._CheckFileName("lpt9.foo"),
     "Sorry, /public/lpt9.foo contains LPT9, which is not compatible with Windows")

  def testDeleteBadFile1(self):
    """Check that you can delete a bad filename.
    """
    self.assertEquals(self._CheckFileName("file space", action="D",
                                                          create_first=True), 0)

  def testDeleteBadFile2(self):
    """Check that you can delete another bad filename.
    """
    self.assertEquals(self._CheckFileName("file:badchar", action="D",
                                                          create_first=True), 0)




if __name__ == '__main__':
  unittest.main()
